package uy.org.softtech.cssuite.web.comando;

import static org.springframework.util.Assert.isTrue;
import static org.springframework.util.Assert.notNull;

import java.util.Locale;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;

import uy.org.softtech.cssuite.core.Comando;
import uy.org.softtech.cssuite.core.Controlador.Accion;
import uy.org.softtech.cssuite.core.Modelo;
import uy.org.softtech.cssuite.entidad.finanzas.Cuenta;
import uy.org.softtech.cssuite.excepciones.EntidadNoActualizadaException;
import uy.org.softtech.cssuite.excepciones.EntidadNoCreadaException;
import uy.org.softtech.cssuite.excepciones.EntidadNoEncontradaException;
import uy.org.softtech.cssuite.servicios.ServiciosClientes;
import uy.org.softtech.cssuite.web.modelo.ModeloCuenta;

/**
 * Implementación de {@link Comando} encargado de procesar la solicitud de creacion y/o actualización de la información de una cuenta de cliente
 * 
 * @author fabian.lobo
 * @see Comando#ejecutar(Modelo, BindingResult)
 */
@Component("comando-cuenta")
public class ComandoCuenta extends Comando {
	
	private Logger log = Logger.getLogger(getClass());
	
	// Servicios
	@Resource(name = "servicios-clientes" )
	private ServiciosClientes serviciosClientes;
	
	/**
	 * Método para verificar que todos los parámetros han sido seteados correctamente.
	 * 
	 * @author fabian.lobo
	 */
	@PostConstruct
	public void inicializacion(){
		super.inicializacion();
		
		notNull(serviciosClientes(), "La propiedad [serviciosClientes] de [" + getClass().getName() + "] no ha sido establecida.");
		
		log.info("Comando encargado de procesar la solicitud de actualización de la información de una cuenta de cliente ha sido inicializado.");
	}
	
	@Override
	public void validaModelo(Modelo modelo, BindingResult errores) {
		notNull(modelo, "El modelo no puede ser nulo.");
		isTrue(modelo instanceof ModeloCuenta, "El modelo no es el correcto para este comando.");
		
		ModeloCuenta modeloCuenta = (ModeloCuenta) modelo;
		
		notNull(modeloCuenta.getAccion(), "Accion no puede ser nulo en este modelo.");
		notNull(modeloCuenta.getLocale(), "Locale no puede ser nulo en este modelo.");
		
		Locale locale = modeloCuenta.getLocale();
		Accion accion = modeloCuenta.getAccion();
		Cuenta cuenta = null;
		
		//CAMPOS NO EDITABLES -> ID
		switch(accion) {
		case ACTUALIZAR:
		case ACTIVAR:
		case CANCELAR:
		case CERRAR:
		case DESACTIVAR:
			notNull(modeloCuenta.getId(), "ID no puede ser nulo en este modelo.");
			
			try {
				cuenta = serviciosClientes().buscarCuenta(modeloCuenta.getId());
			} catch (EntidadNoEncontradaException e) {
				log.error(e);
				errores.addError(new ObjectError("modeloCliente", e.getMessage()));
				return;
			}
			break;
		}
		
		switch(accion) {
		case CREAR:
			
			break;
		case ACTUALIZAR:
			
			break;
		case ACTIVAR:
			//Sólo se puede activar una cuenta en estado 'CREADA' o 'INACTIVA'
			switch(cuenta.getEstado()) {
			case ACTIVA:
				errores.addError(new ObjectError("modeloCliente", fuenteMensajes().getMessage("mensaje.activarCuentaActiva", null, "No se puede activar una cuenta ya activa.", locale)));
				break;
			case CANCELADA:
				errores.addError(new ObjectError("modeloCliente", fuenteMensajes().getMessage("mensaje.activarCuentaCancelada", null, "No se puede activar una cuenta cancelada.", locale)));
				break;
			case CERRADA:
				errores.addError(new ObjectError("modeloCliente", fuenteMensajes().getMessage("mensaje.activarCuentaCerrada", null, "No se puede activar una cuenta cerrada.", locale)));
				break;
			}
			
			break;
		case CANCELAR:
			//No se puede cancelar una cuenta en estado 'CANCELADA' o 'CERRADA'
			switch(cuenta.getEstado()) {
			case CANCELADA:
				errores.addError(new ObjectError("modeloCliente", fuenteMensajes().getMessage("mensaje.cancelarCuentaCancelada", null, "No se puede cancelar una cuenta ya cancelada.", locale)));
				break;
			case CERRADA:
				errores.addError(new ObjectError("modeloCliente", fuenteMensajes().getMessage("mensaje.cancelarCuentaCerrada", null, "No se puede cancelar una cuenta cerrada.", locale)));
				break;
			}
			
			break;
		case CERRAR:
			//No se puede eliminar una cuenta en estado 'CERRADA'
			switch(cuenta.getEstado()) {
			case CERRADA:
				errores.addError(new ObjectError("modeloCliente", fuenteMensajes().getMessage("mensaje.cerrarCuentaCerrada", null, "No se puede cerrar una cuenta ya cerrada.", locale)));
				break;
			}
			
			break;
		case DESACTIVAR:
			//Sólo se puede desactivar una cuenta en estado 'ACTIVA'
			switch(cuenta.getEstado()) {
			case CANCELADA:
			case CERRADA:
			case CREADA:
			case INACTIVA:
				errores.addError(new ObjectError("modeloCliente", fuenteMensajes().getMessage("mensaje.desactivarSoloCuentaActiva", null, "Sólo se puede desactivar una cuenta activa.", locale)));
				break;
			}
			break;
		
		}
	}

	@Override
	public void ejecutarComando(Modelo modelo, BindingResult errores) {
		notNull(modelo, "El modelo no puede ser nulo.");
		isTrue(modelo instanceof ModeloCuenta, "El modelo no es el correcto para este comando.");
		
		ModeloCuenta modeloCuenta = (ModeloCuenta) modelo;
		
		notNull(modeloCuenta.getAccion(), "Accion no puede ser nulo en este modelo.");
		notNull(modeloCuenta.getLocale(), "Locale no puede ser nulo en este modelo.");
		
		Accion accion = modeloCuenta.getAccion();
		Locale locale = modeloCuenta.getLocale();
		
		//CAMPOS NO EDITABLES -> ID
		switch(accion) {
		case ACTUALIZAR:
		case ACTIVAR:
		case CANCELAR:
		case CERRAR:
		case DESACTIVAR:
			notNull(modeloCuenta.getId(), "ID no puede ser nulo en este modelo.");
			break;
		}
		
		Cuenta cuenta = null;
		switch(accion) {
		case CREAR:
			try {
				//TODO Extraer datos del modelo
				
				
				serviciosClientes().crearCuenta(cuenta, SERVICIO);
			} catch (EntidadNoCreadaException e) {
				log.error(e);
				errores.addError(new ObjectError("modeloCuenta", fuenteMensajes().getMessage("mensaje.datosNoGuardados", null, "No hemos podido almacenar los datos. Por favor, contacte al administrador del sistema.", locale)));
			}
			break;
		case ACTUALIZAR:
			try {
				//TODO Extraer datos del modelo
				
				
				serviciosClientes().actualizarCuenta(cuenta, SERVICIO);
			} catch (EntidadNoActualizadaException e) {
				log.error(e);
				errores.addError(new ObjectError("modeloCuenta", fuenteMensajes().getMessage("mensaje.datosNoModificados", null, "No hemos podido actualizar los datos. Por favor, contacte al administrador del sistema.", locale)));
			} catch (EntidadNoEncontradaException e) {
				log.error(e);
				errores.addError(new ObjectError("modeloCuenta", fuenteMensajes().getMessage("mensaje.datosNoModificados", null, "No hemos podido actualizar los datos. Por favor, contacte al administrador del sistema.", locale)));
			}
			break;
		case ACTIVAR:
			try {
				serviciosClientes().activarCuenta(modeloCuenta.getId());
			} catch (EntidadNoEncontradaException e) {
				log.error(e);
				errores.addError(new ObjectError("modeloCuenta", fuenteMensajes().getMessage("mensaje.datosNoModificados", null, "No hemos podido actualizar los datos. Por favor, contacte al administrador del sistema.", locale)));
			} catch (EntidadNoActualizadaException e) {
				log.error(e);
				errores.addError(new ObjectError("modeloCuenta", fuenteMensajes().getMessage("mensaje.datosNoModificados", null, "No hemos podido actualizar los datos. Por favor, contacte al administrador del sistema.", locale)));
			}
			break;
		case CANCELAR:
			try {
				serviciosClientes().cancelarCuenta(modeloCuenta.getId());
			} catch (EntidadNoActualizadaException e) {
				log.error(e);
				errores.addError(new ObjectError("modeloCuenta", fuenteMensajes().getMessage("mensaje.datosNoModificados", null, "No hemos podido actualizar los datos. Por favor, contacte al administrador del sistema.", locale)));
			} catch (EntidadNoEncontradaException e) {
				log.error(e);
				errores.addError(new ObjectError("modeloCuenta", fuenteMensajes().getMessage("mensaje.datosNoModificados", null, "No hemos podido actualizar los datos. Por favor, contacte al administrador del sistema.", locale)));
			}
			break;
		case CERRAR:
			try {
				serviciosClientes().cerrarCuenta(modeloCuenta.getId());
			} catch (EntidadNoActualizadaException e) {
				log.error(e);
				errores.addError(new ObjectError("modeloCuenta", fuenteMensajes().getMessage("mensaje.datosNoModificados", null, "No hemos podido actualizar los datos. Por favor, contacte al administrador del sistema.", locale)));
			} catch (EntidadNoEncontradaException e) {
				log.error(e);
				errores.addError(new ObjectError("modeloCuenta", fuenteMensajes().getMessage("mensaje.datosNoModificados", null, "No hemos podido actualizar los datos. Por favor, contacte al administrador del sistema.", locale)));
			}
			break;
		case DESACTIVAR:
			try {
				serviciosClientes().desactivarCuenta(modeloCuenta.getId());
			} catch (EntidadNoActualizadaException e) {
				log.error(e);
				errores.addError(new ObjectError("modeloCuenta", fuenteMensajes().getMessage("mensaje.datosNoModificados", null, "No hemos podido actualizar los datos. Por favor, contacte al administrador del sistema.", locale)));
			} catch (EntidadNoEncontradaException e) {
				log.error(e);
				errores.addError(new ObjectError("modeloCuenta", fuenteMensajes().getMessage("mensaje.datosNoModificados", null, "No hemos podido actualizar los datos. Por favor, contacte al administrador del sistema.", locale)));
			}
			break;
		}
	}

	/*
	 *  GETTERS
	 */
	public ServiciosClientes serviciosClientes() {
		return serviciosClientes;
	}
}
